local M = {}

local generic_opts_any = { noremap = true, silent = true }

local generic_opts = {
   i = generic_opts_any, -- insert
   n = generic_opts_any, -- normal
   v = generic_opts_any, -- visual
   x = generic_opts_any, -- visual_block
   c = generic_opts_any, -- command
   n = generic_opts_any, -- operator_pending
   t = { silent = true }, -- term
}

local default_configuration = {
    i = {
        ["<C-s>"] = "<ESC>:w<CR>",

        ["<A-k>"] = "<ESC>:m.+1<CR>==gi",
        ["<A-i>"] = "<ESC>:m.-2<CR>==gi",
    },

    n = {
        ["="] = "nzz", -- next search target
        ["-"] = "Nzz", -- prev search target
        ["<leader><CR>"] = ":nohlsearch<CR>", -- cancel searched target highlight
        [";"] = { ":", { noremap = true } },
        ["<C-s>"] = ":w<CR>",
        ["s"] = "<Nop>",

        ["C-h>"] = ":%s//g<left><left>",

        ["i"] = "k",
        ["I"] = "5k",
        ["k"] = "j",
        ["K"] = "5j",
        ["j"] = "h",
        ["J"] = "b", -- prev word
        ["L"] = "w", -- next word

        ["sl"] = ":set splitright<CR>:vsplit<CR>",
        ["sj"] = ":set nosplitright<CR>:vsplit<CR>",
        ["si"] = ":set nosplitbelow<CR>:split<CR>",
        ["sk"] = ":set splitbelow<CR>:split<CR>",
        ["sv"] = "<C-w>t<C-w>K",
        ["sh"] = "<C-w>t<C-w>H",
        ["<C-q>"] = "<ESC>:q<CR>",

        ["<leader>i"] = "<C-w>k",
        ["<leader>j"] = "<C-w>h",
        ["<leader>k"] = "<C-w>j",
        ["<leader>l"] = "<C-w>l",

        ["tn"] = ":tabe<CR>",        
        ["tj"] = ":-tabnext<CR>",        
        ["tl"] = ":+tabnext<CR>",        
        ["<C-w>"] = ":tabc<CR>",

        ["h"] = "i",
        ["H"] = "I",
        ["<leader>v"] = "<C-q>",
        ["<A-k>"] = ":m.+1<CR>==", -- move current line/block
        ["<A-i>"] = ":m.-2<CR>==", -- move current line/block
        ["9"] = "0", -- head
        ["0"] = "$", -- tail
    },

    v = {
        ["i"] = "k",
        ["k"] = "j",
        ["j"] = "h",
        ["<"] = "<gv",
        [">"] = ">gv",
        ["9"] = "0", -- head
        ["0"] = "$", -- tail
    },

    x = {
        ["<A-k>"] = ":m'>+1<CR>gv-gv",
        ["<A-i>"] = ":m'<-2<CR>gv-gv",
        ["9"] = "0", -- head
        ["0"] = "$", -- tail
    },

    c = {

    },
}

M.init = function(configuration)
    vim.api.nvim_set_keymap("", "<Space>", "<Nop>", { noremap = true })
    vim.g.mapleader = " "
    vim.g.maplocalleader = " "

    for mode, mapping in pairs(configuration) do
        local opt = generic_opts[mode] or generic_opts_any
        for key, val in pairs(mapping) do
            if type(val) == "table" then
                opt = val[2]
                val = val[1]
            end
            vim.keymap.set(mode, key, val, opt)
        end
    end
end

M.init(default_configuration)
